// $Id: BlinkToRadioC.nc,v 1.6 2010-06-29 22:07:40 scipio Exp $

/*
 * Copyright (c) 2000-2006 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the
 *   distribution.
 * - Neither the name of the University of California nor the names of
 *   its contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/**
 * Implementation of the BlinkToRadio application.  A counter is
 * incremented and a radio message is sent whenever a timer fires.
 * Whenever a radio message is received, the three least significant
 * bits of the counter in the message payload are displayed on the
 * LEDs.  Program two motes with this application.  As long as they
 * are both within range of each other, the LEDs on both will keep
 * changing.  If the LEDs on one (or both) of the nodes stops changing
 * and hold steady, then that node is no longer receiving any messages
 * from the other node.
 *
 * @author Prabal Dutta
 * @date   Feb 1, 2006
 */
#include <Timer.h>
#include "BlinkToRadio.h"

module BlinkToRadioC {
  uses interface Boot;
  uses interface Leds;
  uses interface Timer<TMilli> as Timer0;
  //uses interface Timer<TMilli> as Timer1;
  uses interface Packet;
  uses interface AMPacket;
  uses interface AMSend;
  uses interface Receive;
  uses interface SplitControl as AMControl;

  uses interface SplitControl as SerialControl;
  uses interface AMSend as SerialSend; 
  uses interface Packet as SerialPacket;
  uses interface AMPacket as SerialAMPacket;
  uses interface Receive as SerialReceive[am_id_t id];
}
implementation {

  uint8_t Event[500];
  uint32_t TS[500];
  uint32_t pktNumber[500];
  //uint8_t Resend[500];
  
  am_addr_t dest;
  
  uint32_t indexofwrite = 0;
  uint32_t indexofread = 0;
  //uint32_t indexofcheck = 0;

  uint8_t buffersize = 500;
  uint16_t indexofreadbuffer;
  uint16_t indexofwritebuffer;
  //uint16_t indexofcheckbuffer;  

  uint8_t Event_send;
  uint32_t TS_send;
  uint8_t ResetSIG = 0;
  //uint32_t Number_Received=0;
  //uint32_t Number_Send=0;
  //uint32_t MissedPacketNumber;
  //uint32_t LastPacketNumber;
  uint32_t ReceivedPacketNumber;
  //uint8_t Resend=0;
  
  message_t pkt;
  message_t sf_pkt;
  message_t reset_pkt;
  bool busy = FALSE;
  bool free = TRUE;
  am_addr_t BASESTATION_ADDR = 10;
  am_addr_t NODE_ADDR = 15;  
  
  task void SendRadioMessageTask();
  void CheckPktNumber();

   event void Boot.booted() {
    call AMControl.start();
    call SerialControl.start();      
  }
  
  event void AMControl.startDone(error_t err) {

    if (err == SUCCESS) {
     
          for (indexofwritebuffer=0;indexofwritebuffer<buffersize;indexofwritebuffer++)
    {
    Event[indexofwritebuffer] = 0xff;
    }     
    call Timer0.startPeriodic(TIMER_PERIOD_MILLI); 
    //call Timer1.startPeriodic(TIMER_PERIOD_CHECK); 
         }
    else {
      call AMControl.start();
    }
  }

  event void AMControl.stopDone(error_t err) {}


  event void SerialControl.startDone(error_t err){}

  event void SerialControl.stopDone(error_t err){}

  event void Timer0.fired() {       

   call Leds.led0Toggle();
    
 if(indexofread < indexofwrite){ 
     
     sf_msg* sf_payload = (sf_msg*)call SerialPacket.getPayload(&sf_pkt, sizeof(sf_msg));
     indexofreadbuffer = indexofread % buffersize;
     
     Event_send = Event[indexofreadbuffer];
     TS_send = TS[indexofreadbuffer];
     
   //if (Event_send != 0xff)
   //{    
        
        sf_payload-> Event1 = Event[indexofreadbuffer];;
        sf_payload->TS1 = TS[indexofreadbuffer];  
        sf_payload->ReceivedPacketNumber = pktNumber[indexofreadbuffer]; 
        //sf_payload->Resend =Resend[indexofreadbuffer];    
   if(busy){return;}
   else{
       if(sf_payload == NULL) {return;}
       if(call SerialPacket.maxPayloadLength() < sizeof(sf_msg)){
       return;}
      if(call SerialSend.send(AM_BROADCAST_ADDR, &sf_pkt, sizeof(sf_msg)) == SUCCESS){
	busy = TRUE;}
      }
   //}
   }
  }

  

  event message_t* Receive.receive(message_t* msg, void* payload, uint8_t len){
    if (len == sizeof(BlinkToRadioMsg)) {
      BlinkToRadioMsg* btrpkt = (BlinkToRadioMsg*)payload;      
      ReceivedPacketNumber = btrpkt->Number_Send;//packet number
      indexofwritebuffer = indexofwrite % buffersize;
      pktNumber[indexofwritebuffer] = btrpkt->Number_Send;//packet number
      Event[indexofwritebuffer] = btrpkt->Event1;
      TS[indexofwritebuffer] = btrpkt->TS1;         
      //Resend[indexofwritebuffer] = btrpkt->Resend;       
       
      //Number_Received++;
      indexofwrite ++;
      call Leds.led1Toggle();
    }
    return msg;
  }


event message_t *SerialReceive.receive[am_id_t id](message_t *msg,
						   void *payload,
						   uint8_t len) 
    {        
        message_t *ret = msg;
	dest = call SerialAMPacket.destination(msg);		
	
        
       if (len == sizeof(ResetMsg)) {
       ResetMsg* resetpkt = (ResetMsg*)payload;      
       ResetSIG = resetpkt->ResetSIG;
      	 if (ResetSIG == 1)
         {      
                atomic {
			indexofwrite = 0;
                        indexofread = 0;
                        }
		post SendRadioMessageTask();        
		call Leds.led2On();
         }
    	else {
                call Leds.led2Off();
          }
     }
			
	return ret;  
    } 
   
task void SendRadioMessageTask(){
if(free){
 ResetMsg* resetpkt = 
	(ResetMsg*)(call Packet.getPayload(&reset_pkt, sizeof(ResetMsg)));
      if (resetpkt == NULL) {
	return;
      }
      resetpkt->ResetSIG = 1;    

     if (call AMSend.send(NODE_ADDR, 
	  &reset_pkt, sizeof(ResetMsg)) == SUCCESS) {
	free = FALSE; //call Leds.led2Toggle();
      }
    } 
}

/*
event void Timer1.fired(){        

      uint32_t IndexWrite;
 
     atomic{IndexWrite = indexofwrite;}
      
      if (indexofcheck < IndexWrite)
{           
      indexofcheckbuffer = indexofcheck % buffersize;
      ReceivedPacketNumber =  pktNumber[indexofwritebuffer]; 

      if(ReceivedPacketNumber == 1) {LastPacketNumber = 0;}

      if(ReceivedPacketNumber < LastPacketNumber) { }

      else if( ReceivedPacketNumber - LastPacketNumber == 1 ) {LastPacketNumber = ReceivedPacketNumber;}
  
      else if( ReceivedPacketNumber - LastPacketNumber == 2 )
           {LastPacketNumber = ReceivedPacketNumber; 
            MissedPacketNumber = ReceivedPacketNumber - 1;  
            post SendRadioMessageTask();} 

      else{LastPacketNumber = ReceivedPacketNumber;}    

} 
}
*/      


event void AMSend.sendDone(message_t* msg, error_t err) {free = TRUE;}

event void SerialSend.sendDone(message_t* msg, error_t err) {busy = FALSE;indexofread++;}

}
